package interpreter;

import token.*;

public class Lexer {
    private String jsonText;
    private int pos;
    private Character currentChar;
    private boolean isStringValue = false;

    public Lexer(String jsonText) {
        this.jsonText = jsonText;
        this.pos = 0;
        this.currentChar = this.jsonText.charAt(pos);
    }

    private void error() throws Exception {
        throw new Exception("Invalid character");
    }

    private void advance() {
        pos++;
        if (pos > jsonText.length() - 1) {
            this.currentChar = null;
        } else {
            this.currentChar = jsonText.charAt(pos);
        }
    }

    private Character preChar() {
        int prePos = pos - 1;
        if (prePos < 0) {
            return null;
        } else {
            return jsonText.charAt(prePos);
        }
    }

    boolean isWhitespace(char x) {
        return x == ' ' || x == '\t' || x == '\n';
    }

    private void skipWhitespace() {
        while (currentChar != null && isWhitespace(currentChar)) {
            this.advance();
        }
    }

    private int integer() {
        StringBuilder sb = new StringBuilder();
        while (currentChar != null && Character.isDigit(currentChar)) {
            sb.append(currentChar);
            this.advance();
        }
        return Integer.parseInt(sb.toString());
    }

    private void checkOneByOne(String b) throws Exception {
        char[] chars = b.toCharArray();
        for (char each : chars) {
            if (each != currentChar)
                throw new Exception("Boolean Error");
            advance();
        }
    }

    private boolean getBooleanValue() throws Exception {
        boolean res;
        if (currentChar == 't') {
            try {
                checkOneByOne("true");
            } catch (Exception e) {
                System.out.println(e.getMessage());
                throw new Exception("Do you mean true?");
            }
            res = true;
        } else {
            try {
                checkOneByOne("false");
            } catch (Exception e) {
                System.out.println(e.getMessage());
                throw new Exception("Do you mean false?");
            }
            res = false;
        }
        return res;
    }

    private String _id() {
        StringBuilder sb = new StringBuilder();
        while (currentChar != '\"' || preChar() == '\\') {
            sb.append(currentChar);
            advance();
        }
        return sb.toString();
    }

    public Token getNextToken() throws Exception {
        while (currentChar != null) {
            if (isWhitespace(currentChar)) {
                skipWhitespace();
                continue;
            }
            if (isStringValue && currentChar!= '\"'){
                String s = _id();
                return new TK_String(s);
            }
            // Boolean类型 true | false
            if (currentChar == 't' || currentChar == 'f') {
                boolean booleanValue = getBooleanValue();
                return new TK_Boolean(booleanValue);
            }
            // 整数类型
            if (Character.isDigit(currentChar)) {
                return new TK_Integer(this.integer());
            }
            switch (currentChar) {
                case ':':
                    advance();
                    return new TK_Assign();
                case '.':
                    advance();
                    return new TK_Dot();
                case '{':
                    advance();
                    return new TK_Lbrace();
                case '}':
                    advance();
                    return new TK_Rbrace();
                case '[':
                    advance();
                    return new TK_Lbracket();
                case ']':
                    advance();
                    return new TK_Rbracket();
                case ',':
                    advance();
                    return new TK_Comma();
                case '\"':
                    isStringValue = !isStringValue;
                    advance();
                    return new TK_Quotation();
                default:
                    error();
                    break;
            }
        }
        return new TK_EOF();
    }
}
